/**
 * 
 */
package com.googlecode.xcarve.config.refer;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.googlecode.xcarve.config.ConfigRefer;
import com.googlecode.xcarve.netty.client.CarveTemplate;
import com.googlecode.xcarve.netty.client.JdkProxy;
import com.googlecode.xcarve.netty.client.NettyClient;
import com.googlecode.xcarve.netty.client.ProxyFactory;
import com.googlecode.xcarve.transport.Client;

/**
 * @author xinyun.d
 * 2014年11月1日
 */
public abstract class AbstractRefer<T> extends ConfigRefer implements DisposableBean{
	private transient volatile   T        ref;
	private transient volatile boolean    initialized;
	private volatile List<Client> listClient;
	static final Logger logger = LoggerFactory.getLogger(AbstractRefer.class);
	
	protected T getRef(){
		if(ref == null){
			synchronized (this) {
				if(ref == null){
					init();
				}
			}
		}
		return ref;
	}
	
	private void init(){
		if(initialized){
			return;
		}
		initialized = true;
		ref = createProxy();
	}
	
	private T createProxy(){
		if(CollectionUtils.isEmpty(listClient)){
			String service = toServicePath();
			List<String> list = getZkInstance().getChildren(service);
			if(CollectionUtils.isEmpty(list)){
				logger.warn("xcarve not found service={} provider, please check refer bean.",this.getInterfaceName());
				throw new IllegalArgumentException("not found service provider, service="+this.getInterfaceName());
			}
			logger.info("xcarve find service provider, service={} has {} server provider", service , list.size());
			List<Client> list_clients = Lists.newArrayList();
			for(int i=0;i<list.size(); i++){
				String servie = list.get(i);
				ConfigRefer config = JSONObject.parseObject(servie, ConfigRefer.class);
				final NettyClient client = new NettyClient(config);
				if(client != null){
					list_clients.add(client);
					logger.info("xcarve establish to server successfull, serverAddress={}", config.getAddress());
				}
			}
			this.listClient = list_clients;
		}
		logger.info("xcarve establish connection to server, total connection is = {},service={}, serverHost={}", 
				 listClient == null ? 0 : listClient.size() , getInterfaceName());
		final CarveTemplate template = new CarveTemplate(listClient);
		ProxyFactory proxy = new JdkProxy(template);
		return proxy.getProxy(this.getInterfaceClass());
	}
	
	void subscrible(final CarveTemplate template){
		String consumer = toConsumerPath();
		getZkInstance().subscrible(consumer,new NotifyListener() {
			@Override
			public void notify(String servicePath,List<String> currentChilds) {
				logger.info("service provider has changed, this serivce has child: {}", getInterfaceName());
				List<Client> list = new ArrayList<Client>();
				for(String child : currentChilds){
					ConfigRefer config = null;
					try {
						config = JSONObject.parseObject(child, ConfigRefer.class);
					} catch (Exception e) {
						continue;
					}
					String address = config.getAddress();
					Client client = NettyClient.clientMap.get(address);
					if(client == null){
						client = new NettyClient(config);
					}
				    list.add(client);
				}
				template.changed(list,getInterfaceName());
			}
		});
		logger.info("service consumer register to zookeeper successfull and add listener. consumer={}", consumer);
	}
	
	@Override
	public void destroy() throws Exception {
		if(!CollectionUtils.isEmpty(listClient)){
			for(Client clt : listClient){
				if(!clt.isClosed()){
					clt.close();
				}
			}
		}
		
		
	}
	
	
}
